package bsserver.response;

import bsserver.Request;
import bsserver.RequestURI;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Response class for handling CGI Script execution
 * @author tblackstone
 */
public class ScriptResponse extends Response {

    private Request r;

    /**
     * Creates a new Script Response object
     * @param r the Request which caused this Response to be generated
     */
    public ScriptResponse(Request r) {
        super(r);
        this.r = r;
    }

    /**
     * Outputs the result of running the CGI script to the given output stream.
     * The message body (if given) from the client is also written to the
     * script's input stream.
     * @param out the output stream to write the script's output to
     * @return tthe number of bytes written to the OutputStream
     */
    @Override
    public int printResponse(OutputStream out) {

        if (r.getRequestURI() == null) {

            System.out.println("ERROR: requestURI is null");
        }

        RequestURI requestURI = r.getRequestURI();
        // Get query string (the stuff after '?')
        String query = requestURI.getQueryString();

        int length = 0;
        try {

            File scriptFile = new File(requestURI.getAbsolutePath());
            BufferedReader scriptReader = new BufferedReader(
                    new FileReader(scriptFile));

            String interpreterPath = scriptReader.readLine();
            if (!interpreterPath.startsWith("#!")) {
                throw new IOException("exec header invalid");
            }
            interpreterPath = interpreterPath.substring(2).trim();
            scriptReader.close();

            ProcessBuilder cgiScript = new ProcessBuilder(interpreterPath,
                    requestURI.getAbsolutePath());

            Map<String, String> envVars = cgiScript.environment();

            // Set non-request specific variables in environment



            envVars.put("SERVER_ADDR", InetAddress.getLocalHost().toString());
            envVars.put("SERVER_SOFTWARE", bsserver.Main.getServerInfo());
            envVars.put("SERVER_NAME", bsserver.Main.HttpdConfig.get("ServerName"));
            envVars.put("GATEWAY_INTERFACE", "CGI/1.1");
            envVars.put("DOCUMENT_ROOT", bsserver.Main.HttpdConfig.get("DocumentRoot"));

            // Set request-specific variables in environment
            envVars.put("SERVER_PROTOCOL", r.getHTTPVersion());
            envVars.put("SERVER_PORT", bsserver.Main.HttpdConfig.get("Listen"));
            envVars.put("REQUEST_METHOD", r.getMethod());
            envVars.put("PATH_INFO", r.getRequestURI().getPathInfoString());
            envVars.put("PATH_TRANSLATED", r.getRequestURI().getAbsolutePath());

            envVars.put("SCRIPT_NAME",requestURI.getAbsolutePath().substring(
                    requestURI.getAbsolutePath().lastIndexOf("/") + 1));

            envVars.put("QUERY_STRING", r.getRequestURI().getQueryString());
            envVars.put("REMOTE_ADDR", r.getRemoteHost());
            envVars.put("AUTH_TYPE", "Basic"); // did not implement digest
            envVars.put("REMOTE_USER", r.getRemoteUser());




            // post
            if (r.getMethod().equals("GET") || r.getMethod().equals("POST")) {


                for (String key : r.getAllHeaders().keySet()) {
                    if (key.equals("Content-Type")) {
                        envVars.put("CONTENT_TYPE",
                                r.getHeader("Content-Type"));
                    } else if (key.equals("Content-Length")) {
                        envVars.put("CONTENT_LENGTH",
                                r.getHeader("Content-Length"));
                    }

                    envVars.put("HTTP_" + key.toUpperCase().replaceAll("-", "_"),
                            r.getHeader(key));

                }

            }

            Process script = cgiScript.start();
            BufferedInputStream in = new BufferedInputStream(script.getInputStream());
            BufferedOutputStream scriptInput = new BufferedOutputStream(script.getOutputStream());

            if (in == null) {
                // Didn't initialize script stream properly
                return 0;
            }

            // don't write if body is null
            if (r.getBody() != null) {
                scriptInput.write(r.getBody());
                scriptInput.flush();
            }

            //Write response status line
            setStatus(200);


            BufferedInputStream error = new BufferedInputStream(script.getErrorStream());


            String outputString = version + " " + statusCode + " " + reasonPhrase + "\r\n";
            byte[] statusLine;
            try {
                statusLine = outputString.getBytes("UTF-8");
            } catch (UnsupportedEncodingException ex) {
                statusLine = outputString.getBytes();
            }
            out.write(statusLine);
            length = length + statusLine.length;

            try {
                script.waitFor();
            } catch (InterruptedException ex) {
                Logger.getLogger(ScriptResponse.class.getName()).log(Level.SEVERE, null, ex);
            }

            while(in.available() > 0){
                out.write(in.read());
                length++;
            }

        } catch (IOException ex) {
            length = (new ErrorResponse(r, 500).printResponse(out));
        }

        return length;

    }
}
